﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using YAXLib;
using RaytracerLib.Samplers;
using RaytracerLib.Resamplers;
using RaytracerLib.Postprocessing.LightCorrector;
using RaytracerLib.Cameras;
using System.Diagnostics;
using RaytracerLib.Postprocessing;
using System.Drawing;

namespace RaytracerLib
{
    public class Film : SceneElement
    {
        [YAXNode]
        public int Width = 600;

        [YAXNode]
        public int Height = 600;

        [YAXNode]
        public int MaxRayDepth = 10;

        private Resampler m_resampler;
        private Sampler m_sampler;

        [YAXCollection]
        private PostprocessorsList m_post_processors = new PostprocessorsList();

        public Film()
        {
            Name = "Film";
            Resampler = Resampler.Create(ResamplerType.Resizer);
            Sampler = Sampler.Create(SamplerType.Grid);
        }

        [YAXNode]
        public Resampler Resampler
        {
            get
            {
                return m_resampler;
            }
            set
            {
                if (m_resampler != null)
                    m_resampler.Film = null;

                m_resampler = value;

                if (m_resampler != null)
                    m_resampler.Film = this;
            }
        }

        [YAXNode]
        public Sampler Sampler
        {
            get
            {
                return m_sampler;
            }
            set
            {
                if (m_sampler != null)
                    m_sampler.Film = null;

                m_sampler = value;

                if (m_sampler != null)
                    m_sampler.Film = this;
            }
        }

        public PostprocessorsList Postprocessors
        {
            get
            {
                return m_post_processors;
            }
        }

        public override Scene Scene
        {
            get
            {
                return base.Scene;
            }
            internal set
            {
                if (Scene == value)
                    return;

                if (Scene != null)
                {
                    foreach (var camera in Scene.Cameras)
                    {
                        if (camera.Film == this)
                            camera.Film = null;
                    }

                    Debug.Assert(!Scene.Films.Contains(this));
                }

                base.Scene = value;

                if (Scene != null)
                {
                    if (!Scene.Films.Contains(this))
                        Scene.Films.Add(this);
                }
            }
        }

        protected override void RenderStart(RenderStartPhase a_phase)
        {
            base.RenderStart(a_phase);

            if (a_phase == RenderStartPhase.PrepareObjectToRender)
            {
                if ((Sampler is NonUniformSampler) && !(Resampler is InterpolateResampler))
                    throw new InvalidOperationException();
            }

            Resampler.RenderStart(a_phase);
            Sampler.RenderStart(a_phase);
        }

        protected override void RenderEnd(bool a_all)
        {
            base.RenderEnd(a_all);

            Resampler.RenderEnd();
        }

        public override string ToString()
        {
            return Name;
        }

        public override bool Remove()
        {
            return Scene.Films.Remove(this);
        }

        public Rectangle GetFilmRect()
        {
            return new Rectangle(0, 0, Width, Height);
        }
    }
}
